除了用户登录操作,SDK 中最重要的就是与设备通讯的任务了。一般情况下会包含以下几个任务:
任务名称 | 任务意义 | 任务作用 |
---|---|---|
XLinkScanDeviceTask | 扫描设备任务 | 扫描同一局域网内的设备以便后续添加订阅和连接 |
XLinkAddDeviceTask | 添加订阅设备任务 | 添加设备,并将设备与用户关联绑定关系,实现任何情况下用户可同步并使用设备 |
XLinkSyncDeviceListTask | 同步设备任务 | 同步与用户关联的设备列表信息 |
XLinkRemoveDeviceTask | 移除设备任务 | 移除设备并取消用户与设备之前的关联关系 |
XLinkTMLProbeAttributeTask | 获取设备物模型属性任务 | 获取设备物模型属性任务 |
XLinkTMLSetAttributeTask | 设置设备物模型属性任务 | 设置设备物模型属性任务 |
XLinkTMLInvokeServiceTask | 调用设备物模型服务 | 调用设备物模型服务 |
1. 设备管理
1.1. 扫描设备任务
对于一个全新的设备,需要通过扫描局域网内的设备发现设备,再进行后续的操作。这是设备操作的首要步骤。
//新建扫描设备任务
XLinkScanDeviceTask *scanTask = [XLinkScanDeviceTask scanDeviceTaskWithProductIdArray:@[@"123456789",@"987654321"]
timeout:90
didDiscoveredDeviceHandler:^(XDevice *device) {
//扫描到设备回调,同一设备仅会回调一次
}
completionHandler:^(id result, NSError *error) {
//无论搜不搜索到设备都会回调这个方法。返回的错误是任务超时
}];
[scanTask start];
在 XLinkScanDeviceTask 中,需要正确传入设备的ProductId(产品ID),对应的设备才会通过扫描回调。同时,支持传入包含多个ProductId 的数组。
注意:扫描设备时需要一些条件限制,请务必确认处于相应环境下才能正常扫描到设备
- APP与扫描的设备必须在同一局域网中
- 确认设备版本与APP支持的版本兼容
若扫描不到设备并无法确认原因,可查看附录FAQ相关问题解答
1.2. 添加订阅设备
添加设备是通过本地与设备通过后,再将校验信息提交到云端,通过云端的校验后将设备与用户形成绑定关系。成功订阅过的设备将在同步设备列表时可以同步到。
XLinkAddDeviceTask *addDeviceTask = [XLinkAddDeviceTask addDeviceTaskWithDevice:device
pinCode:pingCode //pingCode需要硬件设备支持,一般情况下可以为nil
timeout:60
completionHandler:^(id result, NSError *error) {
if (!error) {
//任务执行成功
}else{
//任务执行失败
}
}];
[addDeviceTask start];
在 XLinkAddDeviceTask 中有个属性 needSubscription ,这个属性默认为 YES,已添加成功的设备,SDK会自动在云端建立当前用户账号与设备的订阅关系,并用于后续的数据更新和同步,具体请参考下文的“同步设备”。
如果设置为 NO,则SDK只会添加设备,而不会去订阅设备。关于添加与订阅的差异如下:
操作 | 说明 | 影响 |
---|---|---|
添加设备 | 添加设备为SDK与设备之前建立起联系并从设备获取到部分设备信息(可用于校验工作) | 添加是正常情况下使用设备的前提条件,但是添加操作与云端及用户无直接关联 |
订阅设备 | 通过云端提交设备信息,云端在校验成功后将设备与当前用户绑定关系 | 订阅是保存用户与设备之间关系的必要操作,只有订阅后的设备才能进行远程同步及控制 |
1.3. 同步设备任务
同步设备任务用于将将当前用户的设备设备从云端同步到本地。任务完成后默认自动发起本地连接和云端连接, 同步后的设备会自动添加到设备维护列表中进行维护,设备状态变更时也会有相应的状态回调。
XLinkSyncDeviceListTask *syncTask = [XLinkSyncDeviceListTask syncDeviceListTaskWithVersion:0 //目前只需要填入0即可
timeout:10
connectLocal:YES //同步设备列表后是否需要和设备建立本地连接
completionHandler:^(id result, NSError *error) {
if (!error) {
//任务执行成功,设备列表会通过result返回
}else{
//任务执行失败
}
}];
[syncTask start];
同步设备要求设备和当前用户之间有订阅关系,无订阅关系无法同步到设备。若设备与APP在同一局域网,一般建议 connectLocal-同步后是否进行本地连接设置为 YES 。完全不需要依赖本地通讯的,可以使用 NO,以减少部分资源的维护成本与性能消耗
1.4. 移除设备
移除设备成功时,SDK 会自动从云端解除当前用户与设备之间的订阅关系,并删除与该设备相关的共享和访问权限, 同时也会将该设备移除维护列表, 设备将不能再使用。
//新建删除设备任务
XLinkRemoveDeviceTask *removeDeviceTask = [XLinkRemoveDeviceTask removeDeviceTaskWithDevice:device
timeout:10
completionHandler:^(id result, NSError *error) {
if (!error) {
//任务执行成功
}else{
//任务执行失败
}
}];
[removeDeviceTask start];
1.5. 设备订阅关系管理
通过 XLinkAddDeviceTask 可在云端建立用户和设备之间的订阅关系。订阅关系建立后,可使用 XLinkSyncDeviceListTask 获取与当前用户有订阅关系的设备列表。通过XLinkRemoveDeviceTask可解除订阅关系。
订阅关系 | 操作途径 |
---|---|
订阅关系的建立 | 1.添加设备 2.设备分享 3.其他建立云端订阅关系的途径(如通过二维码订阅) |
订阅关系的解除 | 1.删除设备 2.设备重新激活(设备重置后再连上云端,设备会重新激活) 3.其他解除云端订阅关系的途径 |
1.5.1. 订阅关系变更回调
在订阅关系建立或解除时,以下两个回调会被触发:
1、设备信息变更
- (void)onDeviceChanged:(XDevice *)xDevice withEvent:(XDeviceEvent)event{
switch (event) {
case XDeviceEventSubscribe://与xDevice的订阅关系建立
break;
case XDeviceEventUnSubscribe://与xDevice的订阅关系解除
break;
}
}
2、云端事件推送
- (void)onReceiveEventNotify:(XLinkEventNotify *)eventNotify {
if (eventNotify.messageType == EventNotifyTypeSubscribeChanged) {
}
}
尽管这两个回调都可用,强烈建议统一在 - (void)onDeviceChanged:(XDevice \*)xDevice withEvent:(XDeviceEvent)event
中进行所有设备订阅关系变化的处理,可以避免一些不必要的错误操作。因为实际上**- (void)onDeviceChanged:(XDevice *)xDevice withEvent:(XDeviceEvent)event的回调也是来源于- (void)onReceiveEventNotify:(XLinkEventNotify *)eventNotify,当设备的订阅关系变更时,SDK 将接收到云端的消息推送,并且处理好对应设备的管理,在此过程中会再回调到- (void)onDeviceChanged:(XDevice *)xDevice withEvent:(XDeviceEvent)event**事件中。
当接收到订阅关系变化的通知时,SDK内部已断开和设备的连接,开发者应主动或提示用户刷新设备列表。
以上两个回调依赖云端连接,属于云端的推送消息。主要提供给APP开发者处理订阅关系被动建立或被动解除的情况(例如人为重置设备)。
如果是用户主动添加或删除设备(XLinkAddDeviceTask 或 XLinkRemoveDeviceTask ),那么在执行成功的时候就要进行后续处理,例如刷新设备列表、更新ui等等,不应该等待云端通知再进行处理
1.6. 设备连接状态的刷新
开发 APP 的时候经常需要显示设备的连接状态,很多用例也依赖于设备的连接状态(例如控制设备的时候要求设备在线)。所以如何准确地在 APP 与设备之间同步连接状态是我们首先要解决的问题。
1.6.1. 获取设备连接状态
设备状态可以通过 xDevice.connectionState从设备实体中取出,代码如下:
XDevice *device = [[XDeviceManager shareManager] getDeviceWithMacAddressData:xDevice.macAddress productId:xDevice.productID];
XDeviceConnectionState connectionState = device.connectionState;
1.6.2. 设备连接状态类型
对于连接状态,一个设备默认情况下允许获取到三种状态(连接状态是仅可读的,不允许进行修改,由内部设备维护管理对象维护)
连接状态 | 意义 | 使用场景 |
---|---|---|
localConnectionState | 获取当前设备的本地连接状态(内网) | 当设备仅需要进行内网控制或者是允许进行内网控制时,或者关心设备的内网连接状态时,都可以从此状态获取最新的本地连接状态 |
cloudConnectionState | 获取当前设备的云端连接状态(外网) | 当设备仅需要进行外网控制或者是允许进行外网控制时,或者关心设备的外网连接状态时,都可以从此状态获取最新的云端连接状态 |
connectionState | 获取当前设备的连接状态 | 只要内网或者外网任何一个连接中,该状态值都会返回连接中的状态,当全部断开连接时才会返回断开连接状态 |
大部分使用情况下,通过 connectionState关注设备的连接状态正常即可进行设备的控制。在对设备有特殊环境需求时则可以考虑其它的相关的状态值
对于设备返回的连接状态,主要有三种
状态值 | 意义 |
---|---|
XDeviceConnectionStateDetached | XDevice的状态未知 |
XDeviceConnectionStateOffline | SDK设备与设备失去连接 |
XDeviceConnectionStateConnecting | 设备正在尝试连接中 |
XDeviceConnectionStateOnline | 设备连接成功,设备允许正常通讯 |
1.6.3. 订阅设备状态变化
开发者可以订阅设备的状态变化,通过SDK初始化配置设置状态监听,请参考基础功能使用说明-SDK基本配置。也可以通过设备管理对象对设备状态监听进行注册
//直接对设备管理对象注册设备状态监听事件
XDeviceStateObserver *stateObserver = [XDeviceStateObserver deviceStateChangedObserverWithDevice:_device deviceStateChangedBlock:^(XDevice * _Nonnull device, XDeviceConnectionState state) {
//监听state的变化。
}];
[[XDeviceManager shareManager] addDeviceStateObserver:stateObserver];
设备管理对象对所有注册的设备状态监听事件将会保持强引用,所以请务必记得取消订阅以免引起内存泄漏
//取消监听事件的注册
[[XDeviceManager shareManager] removeDeviceStateObserver:stateObserver];
当stop SDK 的时候,SDK内部会清除所有的设备状态监听事件。
简单地说,如果开发者不关心设备与SDK的连接方式,只需处理 connectionState 即可。当 connectionState`返回XDeviceConnectionStateOnline时,开发者可向设备发送或请求数据。
2. 设备控制
2.1. 设备物模型详解
物模型从属性、服务和事件三个维度,分别描述了其在物理空间中指代的实体是什么,能够做什么,能够对外提供哪些信息。从这三个维度定义好产品相应的物模型之后,也代表定义好了该产品的功能定义。在完成产品功能定义后,系统将自动生成该产品的物模型。
当设备的物模型发生变化,若设备已经连接到云端,那物模型的变化将会通过物联云平台提供的硬件 XAPP SDK,同步到云端上,以便厂商在云平台查看与收集设备的运行状态的变化。
物模型的固定格式
APP 开发者需要创建物模型,并传入SDK中,现在默认的都需要传入字典作为参数。字典中字段 “v” 和 “input” 均为必传字段。
其中 “v” 可以固定传 “2”。”input” 中的 key 是物模型属性定义的name, value 是设备物模型 所需要的值。例如设置物模型属性 “PowerSwitch” 为 YES,则需要设置的 input 为
@{
@"PowerSwitch" : @(YES)
}
以下是调用设置设备属性的服务的示例
NSDictionary *dataPayload = @{
@"v" : @"2",
@"input" : @{
@"key1" : @"value1",
@"key2" : @"value2"
}
};
XLinkTMLSetAttributeTask *task = [XLinkTMLSetAttributeTask setAttributeTaskWithDevice:device dataPayload:dataPayload timeout:10 completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (error) {
NSLog(@"服务调用失败了");
} else {
NSLog(@"服务调用成功了");
}
}];
[task start];
2.2. 获取设备物模型属性
对设备的控制实际上就是对设备的物模型属性进行操作,从而达到设备状态或行为变化。其中获取设备物模型属性使用 XLinkTMLProbeAttributeTask
XLinkTMLProbeAttributeTask *task = [XLinkTMLProbeAttributeTask probeAttributeTaskWithDevice:device dataPayload:dataPayload timeout:10 completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (!error) {
//任务执行成功,物模型属性列表会通过result返回
}else{
//任务执行失败
}
}];
//执行查询物模型属性任务
[task start];
2.3. 设置设备物模型属性
对设备的控制实际上就是对设备的物模型属性进行操作,从而达到设备状态或行为变化。其中设置设备物模型属性使用 XLinkTMLSetAttributeTask
//修改物模型属性,控制设备
NSDictionary *dataPayload = @{
@"v" : @"2",
@"input" : @{
@"PowerSwitch" : @(YES),
@"key2" : @"value2"
}
};
XLinkTMLSetAttributeTask *task = [XLinkTMLSetAttributeTask setAttributeTaskWithDevice:device dataPayload:dataPayload timeout:10 completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (error) {
NSLog(@"服务调用失败了");
} else {
NSLog(@"服务调用成功了");
}
}];
[task start];
2.4. 调用设备物模型服务
相比于属性,服务可通过一条指令实现更复杂的业务逻辑。其中调用设备物模型服务使用 XLinkTMLInvokeServiceTask。
//修改物模型属性,控制设备
NSDictionary *dataPayload = @{
@"v" : @"2",
@"input" : @{
// 这里根据实际填入参数
}
};
NSString *serviceName = @"name"; // 这里根据实际填入服务名
XLinkTMLInvokeServiceTask *invokeServiceTask = [XLinkTMLInvokeServiceTask invokeServiceTaskWithDevice:device serviceName:serviceName dataPayload:dataPayload timeout:10 completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (error) {
NSLog(@"服务调用失败了");
} else {
NSLog(@"服务调用成功了");
}
}];
[invokeServiceTask start];
3. 设备分享管理
3.1 概述
设备的分享管理包括以下几部分:
- 将设备分享给其它用户
- 分享消息推送
- 处理分享消息
- 获取分享列表
3.2 分享设备
通过 XLinkShareDeviceTask 可以将设备权限分享给其他在平台里已经注册的同一企业下用户。
/** 创建一个分享设备task
@param device 设备
@param account 对方账号(邮箱或者手机号)
@param expired 分享有效期时间(单位秒)
@param shareDeviceMode 分享的方式
@param authority 对设备的控制权限,R可读,W可写,RW可读可写;默认为null相当于RW;
@param timeout task超时时间
@param shareCompleteBlock 完成后的回调
*/
XLinkShareDeviceTask *shareTask = [XLinkShareDeviceTask shareDeviceTaskWithDevice:device
account:account
expired:@"7200"
shareMode:XLinkShareDeviceModeApp
authority:@"RW"
timeout:10
completionHandler:^(id result, NSError *error) {
if (!error) {//分享成功
}else{//分享失败
}
}];
[shareTask start];
- 分享的模式类型
类型 | 说明 |
---|---|
XLinkShareDeviceModeApp | 通过用户ID分享 |
XLinkShareDeviceModeQrcode | 二维码方式分享 |
XLinkShareDeviceModeEmail | 邮件方式分享 |
- 设备操作权限
类型 | 说明 |
---|---|
@”R” | 只读 |
@”W” | 只写 |
@”RW” | 可读写 |
3.3 分享消息推送
当接受分享方在线时,对方的XLinkCloudDelegate中的 onReceiveEventNotify 会收到类型为 EventNotifyTypeDeviceShare
的通知:
/** * 当SDK连接上云端,并接收到云端推送时,会回调这个方法。 * * @param eventNotify 收到的云端推送信息 */
- (void)onReceiveEventNotify:(XLinkEventNotify *)eventNotify {
if (eventNotify.messageType == EventNotifyTypeDeviceShare) {
//接收到的类型和设备分享相关
}
}
注意:分享仅会有EventNotify的通知,设备订阅状态变更
- (void)onDeviceChanged:(XDevice *)xDevice withEvent:(XDeviceEvent)event
的回调。
由于分享的设备还不存在当前用户的维护列表中,是无法回调通知设备状态发送了变化的
开发者可通过 EventNotifyHelper 来获取分享的类型,如下所示:
- (void)onReceiveEventNotify:(XLinkEventNotify *)eventNotify {
if (eventNotify.messageType == EventNotifyTypeDeviceShare) {
//解析出设备分析事件
XLinkDeviceShareNotify *shareNotify = [EventNotifyHelper parseDeviceShareNotifyWithData:eventNotify.notifyData];
switch (shareNotify.shareState) {
case DeviceShareStateShareRequest:
//接收到分享请求
break;
case DeviceShareStateAcceptShare:
//接受分享
break;
case DeviceShareStateDenyShare:
//拒绝分享
break;
case DeviceShareStateShareCancel:
//分享被取消
break;
}
}
}
3.4 处理分享消息
开发者可以使用 XLinkHandleShareDeviceTask 对分享进行处理,如下所示:
XLinkHandleShareDeviceTask *handleTask = [XLinkHandleShareDeviceTask handleShareDeviceTaskWithInviteCode:invite_code
handleShareAction:XLinkHandleShareDeviceActionAccept
timeout:20
completionHandler:^(id result, NSError *error) {
if(!error){//处理成功
}else{//处理失败
}
}];
[handleTask start];
其中 Action 为分享处理的行为:
行为 | 操作对象 | 说明 |
---|---|---|
XLinkHandleShareDeviceActionAccept | 被分享者 | 接受该次分享 |
XLinkHandleShareDeviceActionAcceptQrCode | 被分享者 | 接受该次二维码分享 |
XLinkHandleShareDeviceActionDeny | 被分享者 | 拒绝这次分享 |
XLinkHandleShareDeviceActionCancel | 发起分享者 | 取消已经分享出去的分享记录 |
XLinkHandleShareDeviceActionDeleteRecord | 被分享者或发起分享者 | 删除该次分享记录 |
详情可参考 demo 中关于设备分享部分的代码及注释
3.5 获取分享列表
当APP不在线时,可能收不到设备分享的推送消息,这时候可以通过获取分享列表的接口拿到所以接收到分享的数据
获取的方法如下:
[XLinkRestKit getShareDeviceListWithCompletionHandler:^(id _Nullable result, NSError * _Nullable err) {
if(!err){//获取成功
}else{//获取失败
}
}];
成功获取的分享列表数据如下:
[
{
"invite_code" : 分享邀请码,
"from_id" : 分享者ID,
"from_user" : 分享者帐号,
"to_id" : 被分享者ID,
"to_user" : 被分享者帐号,
"device_id" : 设备ID,
"state" : 分享状态
"create_date" : 分享产生时间,
"expire_date" : 分享过期时间,
"authority" : 分享权限
},
]
字段 | 是否必须 | 描述 |
---|---|---|
invite_code | 是 | 分享ID |
authority | 否 | 对设备的控制权限,R可读,W可写,RW可读可写;默认为null相当于RW;同时用户可以扩展这个权限如RW+-等等,这个权限会在订阅时进入用户和设备的authority属性; |
from_id | 是 | 分享者ID,一般都是设备管理员的ID。 |
from_user | 是 | 分享者帐号,一般都是设备管理员的ID。 |
to_id | 是 | 分享给谁 |
to_user | 是 | 分享给谁的帐号 |
device_id | 是 | 设备ID |
state | 是 | 分享状态 |
create_date | 是 | 分享产生时间 |
expire_date | 是 | 分享过期时间 |
分享状态
值 | 类型 | 说明 |
---|---|---|
pending | string | 等待接收 |
accept | string | 已接收 |
deny | string | 拒绝 |
overtime | string | 超时 |
cancel | string | 已取消 |
invalid | string | 无效的请求 |